package com.such.kit;

import java.io.File;
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import javax.xml.XMLConstants;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
import org.xml.sax.ErrorHandler;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import com.such.kit.message.bean.Messager;
import com.such.kit.message.bean.MessageItem;
import com.such.kit.string.StringCommons;
import com.such.kit.validate.ValidateCommons;

/**
 * @author SUCH
 * <pre>
 * xml 通用操作工具类
 * </pre>
 */
public class XmlCommons {

	/**
	 * <pre>
	 * 格式化 xml 文档
	 * </pre>
	 * @param xml xml 字符串
	 * @param charset 字符串编码
	 * @return 格式化后的 xml 文档
	 * @throws DocumentException
	 * @throws IOException
	 */
	public static String formatXml(String xml, String charset) 
			throws DocumentException, IOException {
		SAXReader reader = new SAXReader();
		StringReader in = new StringReader(xml);
		Document document = reader.read(in);
		document.setXMLEncoding(charset);
		return formatXml(document);
	}

	/**
	 * <pre>
	 * 格式化 xml 文档
	 * </pre>
	 * @param document xml 文档
	 * @return 格式化后的 xml 文档
	 * @throws DocumentException
	 * @throws IOException
	 */
	public static String formatXml(Document document) 
			throws DocumentException, IOException {
		OutputFormat formater = OutputFormat.createPrettyPrint();
		formater.setEncoding(document.getXMLEncoding());
		formater.setIndent(StringCommons.RETRACT);
		StringWriter out = null;
		XMLWriter writer = null;
		try {
			out = new StringWriter();
			writer = new XMLWriter(out, formater);
			writer.write(document);
		} finally {
			if (ValidateCommons.isNotEmpty(writer)) {
				writer.close();
			}
		}
		return out.toString();
	}

	/**
	 * <pre>
	 * 基于 xsd 检验 xml 合规性
	 * </pre>
	 * @param xsdPath xsd 路径
	 * @param xmlPath xml 路径
	 * @return 校验结果
	 * @throws SAXException
	 * @throws IOException
	 */
	public static Messager<SAXParseException> validateXml(String xsdPath, String xmlPath) 
			throws SAXException, IOException {
		final Messager<SAXParseException> messager = new Messager<SAXParseException>();
        SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
        Schema schema = factory.newSchema(new File(xsdPath));
        Validator validator = schema.newValidator();
        validator.setErrorHandler(new ErrorHandler() {
			@Override
			public void warning(SAXParseException e) throws SAXException {
				error(e);
			}

			@Override
			public void fatalError(SAXParseException e) throws SAXException {
				error(e);
			}

			@Override
			public void error(SAXParseException e) throws SAXException {
				MessageItem<SAXParseException> mi = new MessageItem<SAXParseException>(e, StringCommons.merger("文档异常位置 [", e.getLineNumber(), ", ", e.getColumnNumber(), "]"), 
						Messager.STATUS_ERROR);
				mi.addContent(e.getMessage());
				messager.addItem(mi);
			}
		});
        validator.validate(new StreamSource(new File(xmlPath)));
        return messager;
    }

}
